﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using IRCTest;
using System.Threading;
using System.Windows.Threading;
using System.Threading.Tasks;
using System.Windows.Controls.Primitives;
namespace WpfApplication1
{
    
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
        public List<User> Users = new List<User>();
        private IRCBot Bot;
       		public MainWindow()
		{
			this.InitializeComponent();
            this.CommandButtons.IsVisibleChanged += new DependencyPropertyChangedEventHandler(Command_Buttons_Loaded);
            this.Loginbtns.LoginBtn.Click +=new RoutedEventHandler(Login_pressed);
            this.CommandButtons.Noticebtn.Click += new RoutedEventHandler(Noticebtn_Click);
            this.CommandButtons.Kickbtn.Click += new RoutedEventHandler(Kickbtn_Click);
            this.CommandButtons.Slap.Click += new RoutedEventHandler(Slap_Click);
            this.Cp1.Members.ItemsSource = Users;
            this.Cp1.ChangeName();
            
        }
        
        void Slap_Click(object sender, RoutedEventArgs e)
        {
            Bot.Actions.Slap(this.Cp1.UserInput.Text, this.Cp1.ChannelCb.SelectedValue.ToString());
        }

        void Kickbtn_Click(object sender, RoutedEventArgs e)
        {
            Bot.Actions.Kick(this.Cp1.UserInput.Text, this.Cp1.ChannelCb.SelectedValue.ToString(), "Derped");
        }

        

        private void Command_Buttons_Loaded(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (!this.CommandButtons.IsVisible || Bot != null)
                return;
            
            ContextMenu Menu = new ContextMenu();
            MenuItem Slap = new MenuItem();
            Slap.Header = "Slap";
            Slap.Click += (s, ev) => { if (this.Cp1.Members.SelectedIndex != -1) { User Member = this.Cp1.Members.SelectedItem as User; Bot.Actions.Slap(Member.Username, this.Cp1.ChannelCb.SelectedItem.ToString()); } };
            Slap.Width = Menu.Width;
            MenuItem Kick = new MenuItem();
            Kick.Header = "Kick";
            Kick.Click += (s, ev) => { if (this.Cp1.Members.SelectedIndex != -1) { User Member = this.Cp1.Members.SelectedItem as User; Bot.Actions.Kick(Member.Username, this.Cp1.ChannelCb.SelectedItem.ToString(),""); } };
            MenuItem PrivChat = new MenuItem();
            PrivChat.Header = "Pm";
            PrivChat.Click += (s, ev) => { if (this.Cp1.Members.SelectedIndex != -1) { User Member = this.Cp1.Members.SelectedItem as User; CreateChat(Member.Username, null); } };
            Menu.Items.Add(Slap);
            Menu.Items.Add(Kick);
            Menu.Items.Add(PrivChat);
            this.Cp1.Members.ContextMenu = Menu;

            Bot = new IRCBot("Falco", "Sk0tchParuche", "#FlamingFalcons", "#FF");
            this.Loginbtns.LoginBtn.Click += new RoutedEventHandler(Login_pressed);
            
            try
            {
                Bot.onMessageReceived += new IRCMEvent(HandleMessage);
                Bot.onUserEvent += new IRCUEvent(UserAction);
                Bot.onCommand += new IRCCEvent(CommandReceived);
                Bot.onUserCheck += new IRCListEvent(onUserCheck);
                Bot.onMessageSend += new BotMessageSend(MessageSend);
                Bot.onPrivMsg += new IRCPmEvent(PrivMsg);
                Bot.onKick += new IRCKicked(UserKicked);
                Task Derp = Task.Factory.StartNew(() => {
                    try{

                        Bot.RUN();
                        
                    }
                    catch(Exception exc){
                        this.Dispatcher.Invoke(new Action(() => {
                        this.Cp1.Output.AppendText("\r\n" + exc.Message); 
                        this.CommandButtons.Visibility = System.Windows.Visibility.Collapsed;
                        this.Loginbtns.Visibility = System.Windows.Visibility.Visible;
                        }
                        ),null);
                    }                
                });

                this.CommandButtons.Saybtn.Click += new RoutedEventHandler(Saybtn_Click);
            }
            catch (Exception ex)
            {
                Title = ex.Message;
            }        
        }

        void UserKicked(object IRCBotInstance, IRCKick Event)
        {
            RemoveChannelOrUser(Event);
        }

        void PrivMsg(object IRCBotInstance, IRCPrivMsg Event)
        {
            this.Dispatcher.Invoke(new Action(() =>
            {

                var exists = from Chats in TabCollection.Items.Cast<TabItem>() where Chats.Header.Equals(Event.User) select Chats;
                if (exists.Count() == 0)
                    CreateChat(Event.User,Event.Message);
                else
                {
                    Conversation Chat = (exists.FirstOrDefault().Content as Conversation);
                    //BindingExpression binding = Chat.GetBindingExpression(Chat.Conv as DependencyProperty);
                    Chat PrivChat = (Chat.LayoutRoot.DataContext as Chat);
                    //Chat.input.Text = Event.User + ":" + Event.Message;
                    //GetBindingExpression((DependencyProperty)Chat.input.Text.);
                    PrivChat.Log = Event.User +": " + Event.Message;
                    
                    

                }
            }));
        }

        private void MessageSend(object IRCBotInstance, MessageSendEvent Event)
        {
            updateOutput(Bot.Nick + "(" + Event.Receipient +")", Event.Message);
        }

        private void Login_pressed(object sender, RoutedEventArgs e)
        {
            this.Loginbtns.Visibility = System.Windows.Visibility.Collapsed;
            this.CommandButtons.Margin = this.Loginbtns.Margin;
            this.CommandButtons.Visibility = System.Windows.Visibility.Visible;            
        }

        private void onUserCheck(object IRCBotInstance, IRCUserList ListEvent)
        {
            var d = from user in ListEvent.Users select user;
            
            foreach (String user in d)
            {                
                this.Dispatcher.Invoke(new Action(() =>
                {
                    var member = (from person in Users where (person != null) && (person.Username.Equals(user)) select person);
                    int count = member.Count();
                    if (count == 0 && !user.Equals(String.Empty))
                    {
                        User User = new User(user, ListEvent.Channel);
                        Users.Add(User);
                        this.Cp1.Members.Items.Refresh();                        
                    }
                    else if (count == 1)
                    {
                        int index = Users.FindIndex(x => (x.Equals(member.FirstOrDefault())));
                        Users[index].addChannel(ListEvent.Channel);
                        this.Cp1.Members.Items.Refresh();                        
                    }

                    if (user.Equals("Falco") && !this.Cp1.ChannelCb.Items.Contains(ListEvent.Channel))
                    {
                        this.Cp1.ChannelCb.Items.Add(ListEvent.Channel);
                        this.Cp1.ChannelCb.SelectedIndex = this.Cp1.ChannelCb.Items.Count- 1;
                    }
                }
               ),null);
            }
        }

        private void Saybtn_Click(object sender, RoutedEventArgs e)
        {
            this.Bot.Actions.Send_Message2(this.Cp1.UserInput.Text,this.Cp1.ChannelCb.SelectedValue.ToString());
            this.Cp1.UserInput.Text = String.Empty;
        }

        private void Noticebtn_Click(object sender, RoutedEventArgs e)
        {
            Bot.Actions.Notice(this.Cp1.UserInput.Text, this.Cp1.ChannelCb.SelectedValue.ToString());
        }

        private void x_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            ListViewItem x = sender as ListViewItem;
            User M = x.Content as User;
            Window.Title = M.Channel;
        }



        public void CreateChat(String User,String Message)
        {
            Conversation D = new Conversation();
            Chat Der = new Chat(User);
            Der.AddUsers(new User(User, User));
            if (Message != null)
            Der.Log = User + ": " +Message;
            
            D.Users.ItemsSource = Der.Members;
            D.Channel.ItemsSource = Der.Users;
            
            D.LayoutRoot.DataContext = Der;
            TabItem Conv = new TabItem();
            Conv.Header = User;
            D.Conv.Loaded += (s, e) => { };
            
            D.Conv.Unloaded += (s, e) => { };
            
            D.input.KeyUp += (s, e) =>
            {
                if (e.Key == Key.Return && D.input.Text.ToLower().Equals("/quit")) TabCollection.Items.Remove(Conv); else if (e.Key == Key.Return ) { Bot.Actions.Send_Message2(D.input.Text, User); Der.Log = Bot.Nick + ": " + D.input.Text; D.Conv.Document.Focus(); D.Conv.Document.MoveFocus(new TraversalRequest(FocusNavigationDirection.Down)); D.input.Clear(); }
            };
            Conv.Content = D;


            //D.Margin = this.Cp1.Margin;
            TabCollection.Items.Add(Conv);
            TabCollection.SelectedItem = Conv;
        }

        public void HandleMessage(object sender, IRCMessageEvent Event)
        {

            if ((Event.Line.Equals(":NickServ!irc@traviangames.org NOTICE Falco :If you do not change within one minute, I will change your nick.")))
            {
                Bot.Identify();
                Bot.Ask_inv();
                Thread.Sleep(750);

                Bot.Join_Chan();
                Bot.Join_Chan();

                //**---------------Throws Thread Exception-----------------**\\
                //||--------------If not done by dispatcher (Seperates UI Thread)\\
                Action x = new Action(() =>
                {
                    this.Cp1.Output.Document.Blocks.Clear();
                    this.Cp1.Output.AppendText("Logged in !");
                }
                );
                this.Dispatcher.Invoke(x, null);

            }
            else if (!Event.Message.Equals(""))
                updateOutput(Event.User + "(" + Event.Channel + ")", Event.Message);
        }

        public void UserAction(object sender, IRCUserEvent Event)
        {
            try
            {
                if (Event.Joined)
                {
                    AddOrUpdateUser(Event);
                }

                else if (Event.NickChange)
                {
                    var x = Users.FindIndex(c => c.Username.Equals(Event.User));
                    Users[x].Username = Event.NewNick;
                    Users[x].GetData(Event.NewNick);
                    this.Cp1.Members.Items.Dispatcher.BeginInvoke(new Action(() => this.Cp1.Members.Items.Refresh()), null);
                }
                else
                {
                    RemoveChannelOrUser(Event);
                }
            }
            catch (Exception Exc)
            {
                updateOutput("Exception : ", Exc.Message);
            }
        }

        public void CommandReceived(object sender, IRCCommandEvent Event)
        {
            User Sender = Users.SingleOrDefault(x => x.Username.Equals(Event.User));
            if (Sender.ValidUser)
                Bot.Actions.Handle(Event.CommandName, Sender, Event.Channel, Event.Parameters);
            else Bot.Actions.Send_Message2("This privilege is given to our members only :-)", Event.User);
            
        }

        private void updateOutput(String User,String Message)
        {
            this.Dispatcher.Invoke(new Action(() =>
               {

                   this.Cp1.Output.AppendText("\u2028" + User + ":\t" + Message);
                   this.Cp1.Output.ScrollToEnd();
               }));
        }


        private void Quit(object sender, EventArgs e)
        {
            Dispatcher.BeginInvokeShutdown(DispatcherPriority.Send);
            Application.Current.Shutdown();
            Environment.Exit(0);
        }

        private void AddOrUpdateUser(IRCBasicEvent Event)
        {
            Action x = new Action(() =>
            {

                if (!Event.User.Equals(String.Empty))
                {
                    var user = from person in Users where person.Username.Equals(Event.User) select person;
                    if (user.Count() == 0)
                    {
                        User User = new User(Event.User, Event.Channel);
                        Users.Add(User);
                    }
                    if (user.Count() == 1)
                    {
                        int index = Users.FindIndex(u => (u.Equals(user.FirstOrDefault())));
                        Users[index].addChannel(Event.Channel);
                        this.Cp1.Members.Items.Refresh();

                    }
                }

                this.Cp1.Members.Items.Refresh();

            });

            this.Dispatcher.Invoke(x, null);
        }
        private void RemoveChannelOrUser(IRCBasicEvent Event)
        {
            Action x = new Action(() =>
            {
               
                var user = from person in Users where person.Username.Equals(Event.User) select person;
                if (user.Count() > 0 && !Event.User.Equals(""))
                {
                    int index = Users.FindIndex(m => (m.Username.Equals(Event.User)));
                    if (Users[index].isInChannel(Event.Channel) && !Users[index].isOnlyChannel(Event.Channel))
                        Users[index].removeChannel(Event.Channel);
                    else
                        Users.RemoveAt(index);
                    ;
                }
                this.Cp1.Members.Items.Refresh();
            });
            Dispatcher.Invoke(x);
        }
        private void IRCBotAborted()
        {

        }



        
    }
}